#include "Chart.h"
#include <iostream>
#include <cmath>
#include <sstream>
#include <string>
#include <iomanip>
#include <algorithm>
const std::vector<Gdiplus::Color> chart_colors = 
{
    Gdiplus::Color(0xff6a5acd),
    Gdiplus::Color(0xffffd700),
    Gdiplus::Color(0xff7fffd4),
    Gdiplus::Color(0xffff4500),
    Gdiplus::Color(0xff7fff00),
    Gdiplus::Color(0xffff7f50),
    Gdiplus::Color(0xff082e54),
    Gdiplus::Color(0xffff9912),
    Gdiplus::Color(0xffa020f0),
    Gdiplus::Color(0xfff5deb3),
    Gdiplus::Color(0xff00c957),
    Gdiplus::Color(0xff1e90ff),
    Gdiplus::Color(0xff00ff00),
    Gdiplus::Color(0xffff8000),
    Gdiplus::Color(0xff228b22),
    Gdiplus::Color(0xff3d59ab),
    Gdiplus::Color(0xff7cfc00),
    Gdiplus::Color(0xfffffafa),
    Gdiplus::Color(0xffed9121),
    Gdiplus::Color(0xffb0e0e6),
    Gdiplus::Color(0xffe3170d),
    Gdiplus::Color(0xff0000ff),
    Gdiplus::Color(0xffff6100),
    Gdiplus::Color(0xffffff00),
    Gdiplus::Color(0xffff00ff),
    Gdiplus::Color(0xff00ffff),
    Gdiplus::Color(0xfff8f8ff),
    Gdiplus::Color(0xff4169e1),
    Gdiplus::Color(0xff8a2be2),
    Gdiplus::Color(0xff87ceeb)
};
Chart::Chart::Chart(unsigned int width, unsigned int height)
{
    chart_img    = new Gdiplus::Bitmap(width, height);
    chart_g        = new Gdiplus::Graphics(chart_img);
    chart_g->Clear(Gdiplus::Color(255, 255, 255));
    chart_window = NULL;
}

Chart::Chart::~Chart()
{
    delete chart_window;
    delete chart_g;
    delete chart_img;
}

void Chart::Chart::plot()
{
    if (chart_window == NULL)
        chart_window = new PictureDisplayWindow(chart_img);
}

Chart::Pie::Pie() : Chart(390, 260)
{

}

Chart::Pie::Pie(const std::map<std::string, unsigned int> &data) : Chart(630, 500)
{
    set_data(data);
}

void Chart::Pie::set_data(const std::map<std::string, unsigned int> &data)
{
    this->data = data;
}

void Chart::Pie::plot()
{
    using namespace std;
    if (data.empty())
    {
        std::cerr << "[Pie] Illegal data\n";
        return;
    }

    int sum = 0.0;

    map<string, unsigned int>::iterator it;

    for (it = data.begin(); it != data.end(); it++)
        sum += it->second;

    double last_angle = -90.0;


    int color_use = 0;
    for (it = data.begin(); it != data.end(); it++)
    {
        double sweep_angle = it->second / (double)sum * 360.0;
        Gdiplus::SolidBrush brush(chart_colors[color_use++]);
        chart_g->FillPie(&brush, 10, 10, 480, 480, last_angle, sweep_angle);
        last_angle += sweep_angle;
        chart_g->FillRectangle(&brush, 510, 10 + color_use * 20, 20, 20);

        wchar_t *wstr = new wchar_t[it->first.length()];

        MultiByteToWideChar(CP_ACP, 0, (LPCSTR)it->first.c_str(), it->first.length(), wstr, it->first.length());

        chart_g->DrawString(wstr, it->first.length(), &Gdiplus::Font(L"Consolas", 12), Gdiplus::PointF((double)532, (double)(10 + color_use * 20)), &Gdiplus::SolidBrush(Gdiplus::Color(0, 0, 0)));
        delete[] wstr;
    }

    last_angle = -90.0;
    Gdiplus::Pen pen(Gdiplus::Color(0, 0, 0));

    for (it = data.begin(); it != data.end(); it++)
    {
        double sweep_angle = it->second / (double)sum * 360.0;
        chart_g->DrawPie(&pen, 10, 10, 480, 480, last_angle, sweep_angle);
        last_angle += sweep_angle;
    }


    Chart::plot();
}


Chart::LineChart::LineChart() : Chart(480, 800)
{

}

Chart::LineChart::LineChart(std::vector<double> &x_axis, std::vector<double> &y_axis) : Chart(740, 400)
{
    set_data(x_axis, y_axis);
}
void Chart::LineChart::set_data(std::vector<double> &x_axis, std::vector<double> &y_axis)
{
    this->x_axis = x_axis;
    this->y_axis = y_axis;
}
void Chart::LineChart::plot()
{
    using namespace std;
    if (x_axis.empty() || y_axis.empty() || x_axis.size() != y_axis.size() || x_axis.size() < 3 || x_axis.size() >= 100000)
        return;



    int x_width = 600, y_width = 360;
    int size = x_axis.size();

    Gdiplus::Bitmap bmp(x_width, y_width);
    Gdiplus::Graphics g(&bmp);
    g.Clear(0xffc0c0c0);

    double x_min = 1e9, x_max = -(1e9), y_min = 1e9, y_max = -(1e9);

    for (int i = 0; i < size; i++)
    {
        if (x_axis[i] < x_min)
            x_min = x_axis[i];
        if (y_axis[i] < y_min)
            y_min = y_axis[i];
        if (x_axis[i] > x_max)
            x_max = x_axis[i];
        if (y_axis[i] > y_max)
            y_max = y_axis[i];
    }

    double x_range = x_max - x_min, y_range = y_max - y_min;
    Gdiplus::Point points[100000];
    for (int i = 0; i < size; i++)
    {
        points[i].X = ((x_axis[i] - x_min) / x_range * x_width);
        points[i].Y = ((y_axis[i] - y_min) / y_range * y_width);
    }

    sort(points, points + size, [](const Gdiplus::Point &a, const Gdiplus::Point &b){return (a.X == b.X ? (a.Y < b.Y) : (a.X < b.X)); });

    for (int i = 0; i < size; i++)
    {
        points[i].Y = y_width - points[i].Y;
    }

    Gdiplus::Pen pen(0xff308014);
    Gdiplus::Pen blackpen(0xff000000);
    for (int i = 0; i < size-1; i++)
    {
        g.DrawLine(&pen, points[i], points[i+1]);
    }

    chart_g->DrawImage(&bmp, 70, 20);
    chart_g->DrawRectangle(&blackpen, 69, 19, x_width + 1, y_width + 1);
    

    wostringstream xval1, yval1, xval2, yval2;

    xval1 << fixed << setprecision(3) << x_min << L'\0';
    xval2 << fixed << setprecision(3) << x_max << L'\0';
    yval1 << fixed << setprecision(3) << y_min << L'\0';
    yval2 << fixed << setprecision(3) << y_max << L'\0';
    wstring wx1 = xval1.str(), wx2 = xval2.str(), wy1 = yval1.str(), wy2 = yval2.str();
    chart_g->DrawString(wx1.c_str(), wx1.length(), &Gdiplus::Font(L"Consolas", 12), Gdiplus::PointF((double)59, (double)379), &Gdiplus::SolidBrush(Gdiplus::Color(0, 0, 0)));
    chart_g->DrawString(wx2.c_str(), wx2.length(), &Gdiplus::Font(L"Consolas", 12), Gdiplus::PointF((double)59+x_width, (double)379), &Gdiplus::SolidBrush(Gdiplus::Color(0, 0, 0)));
    chart_g->DrawString(wy1.c_str(), wy1.length(), &Gdiplus::Font(L"Consolas", 12), Gdiplus::PointF((double)32, (double)367), &Gdiplus::SolidBrush(Gdiplus::Color(0, 0, 0)));
    chart_g->DrawString(wy2.c_str(), wy2.length(), &Gdiplus::Font(L"Consolas", 12), Gdiplus::PointF((double)32, (double)371-y_width), &Gdiplus::SolidBrush(Gdiplus::Color(0, 0, 0)));
    Chart::plot();

}